package main.computables;

import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;


public class CashedComputable3<A,V> implements Computable<A,V>{
	
	private final ConcurrentHashMap<A,Future<V>> cashe;
	private final Computable<A, V> computable;
	
	public CashedComputable3(Computable<A, V> computable){
		this.computable = computable;
		cashe = new ConcurrentHashMap<A,Future<V>>();
	}
	
	@Override
	public V compute(final A arg) throws InterruptedException {
		Future<V> result = cashe.get(arg);
		if(result == null){
			FutureTask<V> ft = new FutureTask<>(new Callable<V>() {
				@Override
				public V call() throws Exception {
					return computable.compute(arg);
				}
			});
			
			result = cashe.putIfAbsent(arg, ft);
			if(result == null){
				ft.run();
				result = ft;
			}

		}
		
		try {
			return result.get();
		} catch (ExecutionException e) {
			throw new RuntimeException(e);
		}
	}
	

}
